import { App, Provide, Inject } from '@midwayjs/decorator'
import { Application } from 'egg'
import { gql } from 'graphql-request'
import { customAlphabet } from 'nanoid'

import { SystemUserService } from './system-user'

const dayjs = require('dayjs')
const shortid = customAlphabet('0123456789', 6)

const TicketFragment = `
  id
  title
  code
  status
  content
  department {
    id
    name
  }
  ticket_source {
    id
    content
  }
  create_by: system_user_create {
    id
    username
    nickname
  }
  create_at
  create_msg
  accept_by: system_user_accept {
    id
    username
    nickname
  }
  accept_at
  accept_msg
  process_by: system_user_process {
    id
    username
    nickname
  }
  process_at
  process_msg
  attachments: ticket_attachments {
    ie_attachment {
      filename
      filepath
      ext
      id
    }
  }
  attachments_pending: ticket_attachments_pending {
    ie_attachment {
      create_at
      filename
      filepath
      ext
      id
    }
  }
  attachments_sign: ticket_signs {
    ie_attachment {
      create_at
      filename
      filepath
      ext
      id
    }
    bookmarks
  }
  bookmarks
`

export const ENUM_STATUS = {
  APPLIED: 0,
  CANCELLED: 1,
  PENDING: 2,
  PROCESSING: 3,
  DEPRECATED: 4,
  WITHDRAW: 5,
  FAILED: 6,
  COMPLETED: 7
}

@Provide()
export class TicketService {

  @App()
  app: Application

  @Inject()
  systemUserService: SystemUserService

  STATUS = { ...ENUM_STATUS }

  async get(id) {
    try {
      const { ticket_by_pk } = await this.app.gqlRequest(gql`
        query ($id: uuid!) {
          ticket_by_pk (id: $id) {
            ${TicketFragment}
          }
        }
      `, { id })

      const {
        attachments,
        attachments_pending,
        attachments_sign,
        ...ticket
      } = ticket_by_pk

      if (Array.isArray(attachments)) {
        ticket.attachments = attachments.map(({ ie_attachment }) => ie_attachment)
      }
      if (Array.isArray(attachments_pending)) {
        ticket.attachments_pending = attachments_pending.map(({ ie_attachment }) => ie_attachment)
      }
      if (Array.isArray(attachments_sign)) {
        ticket.attachments_sign = attachments_sign.map(({ ie_attachment, bookmarks = [] }) => ({
          ...ie_attachment,
          bookmarks
        }))
      }

      return ticket
    } catch (err) {}
  }

  async add(ticket) {
    const {
      create_by_id,
      ticket_attachments = [],
      ...object
    } = ticket

    try {
      const create_by = await this.systemUserService.get({ id: create_by_id })

      object.create_by_id = create_by_id
      object.status = this.STATUS.APPLIED

      // 自动设置事件归属部门为生成事件人所在部门
      if (create_by?.system_user_meta?.department?.id) {
        object.department_id = create_by.system_user_meta.department.id
      }

      // 自动生成事件编号
      // 后期修改
      object.code = 'QDJB' + dayjs().format('YYYYMMDD') + shortid()

      if (
        Array.isArray(ticket_attachments) &&
        ticket_attachments.length
      ) {
        object.ticket_attachments = {
          data: ticket_attachments.map(id => ({ attachment_id: id }))
        }
      }

      const {
        insert_ticket_one
      } = await this.app.gqlRequest(gql`
        mutation ($object: ticket_insert_input!) {
          insert_ticket_one (object: $object) {
            ${TicketFragment}
          }
        }
      `, { object })

      const {
        attachments,
        ...added
      } = insert_ticket_one

      if (Array.isArray(attachments)) {
        added.attachments = attachments.map(({ ie_attachment }) => ie_attachment)
      }

      return added
    } catch (err) {}
  }

  async update(ticket) {
    const {
      id,
      status,
      process_by_id,
      accept_by_id,
      ...object
    } = ticket

    try {
      object['status'] = this.STATUS[status]
      object['update_at'] = 'now()'

      if (process_by_id) {
        const process_by = await this.systemUserService.get({ id: process_by_id })

        if (process_by) {
          object.process_by_id = process_by_id
        }
      }

      if (accept_by_id) {
        const process_by = await this.systemUserService.get({ id: accept_by_id })

        if (process_by) {
          object.accept_by_id = accept_by_id
        }
      }

      if (['DEPRECATED', 'WITHDRAW', 'FAILED', 'COMPLETED'].indexOf(status) > -1) {
        object['process_at'] = 'now()'
      }

      const {
        update_ticket_by_pk
      } = await this.app.gqlRequest(gql`
        mutation ($id: uuid!, $object: ticket_set_input!) {
          update_ticket_by_pk (
            pk_columns: { id: $id }
            _set: $object
          ) {
            ${TicketFragment}
          }
        }
      `, { object, id })

      const {
        attachments,
        attachments_pending,
        ...updated
      } = update_ticket_by_pk

      if (Array.isArray(attachments)) {
        updated.attachments = attachments.map(({ ie_attachment }) => ie_attachment)
      }
      if (Array.isArray(attachments_pending)) {
        ticket.attachments_pending = attachments_pending.map(({ ie_attachment }) => ie_attachment)
      }

      return updated
    } catch (err) {
      this.app.logger.error(err)
    }
  }

  async addPending(object) {
    try {
      const {
        insert_ticket_attachments_pending_one: inserted
      } = await this.app.gqlRequest(gql`
        mutation ($object: ticket_attachments_pending_insert_input!) {
          insert_ticket_attachments_pending_one (
            object: $object
          ) {
            ie_attachment {
              filename
              filepath
              ext
              id
            }
          }
        }
      `, { object })

      return inserted?.ie_attachment
    } catch (err) {}
  }

  async addSign(object) {
    try {
      const {
        insert_ticket_sign_one: inserted
      } = await this.app.gqlRequest(gql`
        mutation ($object: ticket_sign_insert_input!) {
          insert_ticket_sign_one (
            object: $object
          ) {
            ie_attachment {
              filename
              filepath
              ext
              id
            }
            bookmarks
          }
        }
      `, { object })

      if (inserted) {
        const { ie_attachment, bookmarks } = inserted

        return {
          ...ie_attachment,
          bookmarks
        }
      }
    } catch (err) {}
  }
}